home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Communications / pcomm / Source / x_batch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-12  |  8.7 KB  |  416 lines

  1. /*
  2.  * Routines to support the batch protocols.
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <curses.h>
  8. #include "config.h"
  9. #include "misc.h"
  10. #include "xmodem.h"
  11.  
  12. /*
  13.  * Send the file name for the modem7 batch.  Only uses 11 characters
  14.  * of the filename.  Returns zero on success or the standard error codes.
  15.  */
  16.  
  17. int
  18. send_modem7(win, name)
  19. WINDOW *win;
  20. char *name;
  21. {
  22.     char *new_name;
  23.     static char *fix_name();
  24.     unsigned char sum, calc_sum();
  25.  
  26.                     /* convert to 11 character name */
  27.     new_name = fix_name(name);
  28.     sum = calc_sum((unsigned char *) new_name, 12);
  29.  
  30.     putc_line(ACK);
  31.                     /* for each character in the name */
  32.     while (*new_name != CTRLZ) {
  33.         putc_line((unsigned char) *new_name);
  34.  
  35.         switch (getc_line(3)) {
  36.             case -1:    /* timed out */
  37.                 clear_line(win, 12, 24, TRUE);
  38.                 waddstr(win, "NO RESPONSE");
  39.                 wrefresh(win);
  40.                 return(ERROR);
  41.             case ACK:    /* got it! */
  42.                 break;
  43.             case CAN:    /* cancel transmission */
  44.                 if (getc_line(2) == CAN) {
  45.                     beep();
  46.                     clear_line(win, 12, 24, TRUE);
  47.                     wattrstr(win, A_BOLD, "REMOTE ABORTED");
  48.                     wrefresh(win);
  49.                     return(CANCEL);
  50.                 }
  51.                 /* fall thru... */
  52.             default:
  53.                 clear_line(win, 12, 24, TRUE);
  54.                 waddstr(win, "NAME FAILED");
  55.                 wrefresh(win);
  56.                 return(ERROR);
  57.         }
  58.         new_name++;
  59.     }
  60.     putc_line(CTRLZ);
  61.                     /* verify the checksum */
  62.     if (getc_line(10) != sum) {
  63.         putc_line('u');
  64.         clear_line(win, 12, 24, TRUE);
  65.         waddstr(win, "CHECKSUM FAILED");
  66.         wrefresh(win);
  67.         return(ERROR);
  68.     }
  69.     putc_line(ACK);
  70.     return(0);
  71. }
  72.  
  73. /*
  74.  * Receive a modem7 file name.  Returns zero on success, the standard error
  75.  * codes, or a -1 on the end-of-batch.  (Oddly enough, the end-of-batch code
  76.  * is the same as the code for a user abort)
  77.  */
  78.  
  79. int
  80. rcv_modem7(win, default_err)
  81. WINDOW *win;
  82. int default_err;
  83. {
  84.     extern char file_name[15];
  85.     int i, j, err_method, err_count, got_it;
  86.     unsigned char sum, calc_sum();
  87.     char temp_name[13];
  88.     static void change_name(), unfix_name();
  89.  
  90.     err_method = default_err;
  91.     if (default_err == CRC_CHECKSUM)
  92.         err_method = CRC;
  93.  
  94.     err_count = 0;
  95.     got_it = 0;
  96.     while (err_count < MAX_ERRORS) {
  97.                     /* switch to checksum? */
  98.         if (default_err == CRC_CHECKSUM && err_count > MAX_ERRORS/2)
  99.             err_method = CHECKSUM;
  100.  
  101.         if (err_method == CRC)
  102.             putc_line('C');
  103.         else
  104.             putc_line(NAK);
  105.                     /* what'd we get? */
  106.         switch (getc_line(10)) {
  107.             case -1:    /* timed out */
  108.                 clear_line(win, 12, 24, TRUE);
  109.                 wattrstr(win, A_BOLD, "NO RESPONSE");
  110.                 wrefresh(win);
  111.                 err_count++;
  112.                 break;
  113.             case ACK:    /* ready to go... */
  114.                 got_it++;
  115.                 break;
  116.             default:    /* huh? */
  117.                 clear_line(win, 12, 24, TRUE);
  118.                 wattrstr(win, A_BOLD, "BAD HEADER");
  119.                 wrefresh(win);
  120.                 err_count++;
  121.         }
  122.         if (got_it)
  123.             break;
  124.     }
  125.     if (!got_it)
  126.         return(ERROR);
  127.                     /* get the name */
  128.     for (i=0; i<12; i++) {
  129.         j = getc_line(3);
  130.  
  131.         switch (j) {
  132.             case -1:    /* timed out */
  133.                 clear_line(win, 12, 24, TRUE);
  134.                 wattrstr(win, A_BOLD, "NO RESPONSE");
  135.                 wrefresh(win);
  136.                 return(ERROR);
  137.             case EOT:    /* end of batch? */
  138.                 return(-1);
  139.             case CAN:    /* cancel transmission */
  140.                 if (getc_line(2) == CAN) {
  141.                     beep();
  142.                     clear_line(win, 12, 24, TRUE);
  143.                     wattrstr(win, A_BOLD, "REMOTE ABORTED");
  144.                     wrefresh(win);
  145.                     return(CANCEL);
  146.                 }
  147.                 /* fall thru... */
  148.             case 'u':    /* bad name character */
  149.                 beep();
  150.                 clear_line(win, 12, 24, TRUE);
  151.                 wattrstr(win, A_BOLD, "BAD NAME");
  152.                 wrefresh(win);
  153.                 return(ERROR);
  154.             default:    /* the name... */
  155.                 temp_name[i] = j & 0xff;
  156.                 if (j != CTRLZ)
  157.                     putc_line(ACK);
  158.                 break;
  159.         }
  160.     }
  161.     temp_name[12] = '\0';
  162.                     /* send our checksum */
  163.     sum = calc_sum((unsigned char *) temp_name, 12);
  164.     putc_line(sum);
  165.                     /* do they agree? */
  166.     if (getc_line(10) != ACK) {
  167.         beep();
  168.         clear_line(win, 12, 24, TRUE);
  169.         wattrstr(win, A_BOLD, "BAD NAME");
  170.         wrefresh(win);
  171.         return(ERROR);
  172.     }
  173.                     /* load the file_name array */
  174.     unfix_name(temp_name);
  175.                     /* any name collisions? */
  176.     change_name(win, file_name);
  177.     return(0);
  178. }
  179.  
  180. /*
  181.  * Send the block 0 information for a ymodem batch transfer.  Uses only
  182.  * the name component of the path and the file size.
  183.  */
  184.  
  185. int
  186. send_ymodem(win, file, size)
  187. WINDOW *win;
  188. char *file;
  189. long size;
  190. {
  191.     unsigned short crc, calc_crc();
  192.     char *strcpy(), *memset();
  193.     unsigned char buf[133];
  194.                     /* start with a clean block */
  195.     memset((char *) buf, '\0', 133);
  196.                     /* the header */
  197.     buf[0] = SOH;
  198.     buf[1] = 0;
  199.     buf[2] = 255;
  200.  
  201.     /*
  202.      * The block zero consists of the file name (no path component),
  203.      * a NULL, and the file length (as a string).  The end of batch
  204.      * marker is an empty block.
  205.      */
  206.     if (*file != '\0') {
  207.         strcpy((char *) &buf[3], file);
  208.         sprintf((char *) &buf[strlen(file)+4], "%ld", size);
  209.     }
  210.                     /* the crc */
  211.     crc = calc_crc(&buf[3], 128);
  212.     buf[131] = crc >> 8;
  213.     buf[132] = crc;
  214.                     /* the block count */
  215.     mvwaddstr(win, 7, 24, "0   ");
  216.  
  217.     return(send_block(win, buf, 133));
  218. }
  219.  
  220. /*
  221.  * Receive the block 0 information for a ymodem batch transfer.  We
  222.  * only use the file name and the size (if present).  Currently doesn't
  223.  * support full path names.
  224.  */
  225.  
  226. int
  227. rcv_ymodem(win)
  228. WINDOW *win;
  229. {
  230.     extern unsigned char buf[1029];
  231.     extern long file_length;
  232.     extern char file_name[15];
  233.     int code, length_is_at;
  234.     long atol();
  235.     static void change_name();
  236.  
  237.     file_length = 0L;
  238.     file_name[0] = '\0';
  239.                     /* read the zero block */
  240.     if (code = rcv_block(win, 1, 1024, 0))
  241.         return(code);
  242.                     /* at end of batch */
  243.     if (buf[3] == '\0')
  244.         return(0);
  245.                     /* get the file name */
  246.     change_name(win, (char *) &buf[3]);
  247.                     /* any trouble? */
  248.     if (file_name[0] == '\0') {
  249.         putc_line(CAN);
  250.         return(0);
  251.     }
  252.     /*
  253.      * The file length is placed after the NULL of the file name
  254.      * and is terminated by another NULL.  If the length is missing,
  255.      * atol() will see a NULL and return 0.
  256.      */
  257.     length_is_at = strlen((char *) &buf[3]) + 4;
  258.     file_length = atol((char *) &buf[length_is_at]);
  259.     return(0);
  260. }
  261.  
  262. /*
  263.  * Handle file name collisions.  Prepend an "X" to the name until you find
  264.  * a name that doesn't already exist.  Creates a NULL name on error.
  265.  * Loads the global character array "file_name".
  266.  */
  267.  
  268. static void
  269. change_name(win, str)
  270. WINDOW *win;
  271. char *str;
  272. {
  273.     extern char file_name[15];
  274.     register int i;
  275.     int modified;
  276.     char temp[15], ans[15], *s, *strrchr(), *strcpy(), *strncat();
  277.     char *strncpy();
  278.     unsigned int sleep();
  279.                     /* dissect the name component */
  280.     if ((s = strrchr(str, '/')))
  281.         strncpy(temp, ++s, 15);
  282.     else
  283.         strncpy(temp, str, 15);
  284.     temp[14] = '\0';
  285.  
  286.     strcpy(ans, temp);
  287.     file_name[0] = '\0';
  288.                     /* write permission on directory? */
  289.     if (access(".", 2)) {
  290.         beep();
  291.         clear_line(win, 12, 24, TRUE);
  292.         wattrstr(win, A_BOLD, "NO WRITE ON DIRECTORY");
  293.         wrefresh(win);
  294.         return;
  295.     }
  296.                     /* prepend up to 13 "X"s */
  297.     modified = 0;
  298.     for (i=1; i<14; i++) {
  299.         if (access(ans, 0)) {
  300.             if (modified) {
  301.                 beep();
  302.                 clear_line(win, 12, 24, TRUE);
  303.                 waddstr(win, "NAME COLLISION");
  304.                 wrefresh(win);
  305.                 sleep(1);
  306.             }
  307.             strcpy(file_name, ans);
  308.             return;
  309.         }
  310.  
  311.         modified++;
  312.         strcpy(temp, "X");
  313.         strncat(temp, ans, 13);
  314.         temp[14] = '\0';
  315.         strcpy(ans, temp);
  316.     }
  317.     beep();
  318.     clear_line(win, 12, 24, TRUE);
  319.     waddstr(win, "BAD NAME");
  320.     wrefresh(win);
  321.     return;
  322. }
  323.  
  324. /*
  325.  * Convert a perfectly good Unix file name to fit the CP/M file name
  326.  * rules.  Used for the modem7 batch file transfer.  Returns a pointer
  327.  * to a static area containing the new name.
  328.  */
  329.  
  330. static char *
  331. fix_name(path)
  332. char *path;
  333. {
  334.     int i, dot;
  335.     char *s, *name, temp[15], *ext, *strncpy(), *strrchr();
  336.     static char ans[13];
  337.                     /* ignore the path component */
  338.     if (s = strrchr(path, '/'))
  339.         strncpy(temp, ++s, 15);
  340.     else
  341.         strncpy(temp, path, 15);
  342.     temp[14] = '\0';
  343.     name = temp;
  344.  
  345.     ext = "";
  346.     dot = 0;
  347.     for (i=strlen(temp)-1; i>=0; i--) {
  348.         if (temp[i] == '.' && !dot) {
  349.             dot = 1;
  350.             temp[i] = '\0';
  351.             ext = &temp[i+1];
  352.         }
  353.         if (islower(temp[i]))
  354.             temp[i] = toupper(temp[i]);
  355.     }
  356.                     /* if null name component */
  357.     if (*name == '\0')
  358.         name = "X";
  359.                     /* if name too long */
  360.     if (strlen(name) > 8)
  361.         *(name+8) = '\0';
  362.                     /* if extension too long */
  363.     if (strlen(ext) > 3)
  364.         *(ext+3) = '\0';
  365.  
  366.     sprintf(ans, "%-8.8s%-3.3s%c", temp, ext, CTRLZ);
  367.     return(ans);
  368. }
  369.  
  370. /*
  371.  * Convert a CP/M style filename into a legal Unix file name.  Loads the
  372.  * global character array "file_name".
  373.  */
  374.  
  375. static void
  376. unfix_name(cpm_name)
  377. char *cpm_name;
  378. {
  379.     extern char file_name[15];
  380.     register int i, n;
  381.     int dot;
  382.     char temp[15], *strcpy();
  383.  
  384.     file_name[0] = '\0';
  385.     if (*cpm_name == '\0')
  386.         return;
  387.  
  388.     strcpy(temp, cpm_name);
  389.                     /* 8 character of the name */
  390.     n = 0;
  391.     for (i=0; i<8; i++) {
  392.         if (temp[i] != ' ') {
  393.             if (isupper(temp[i]))
  394.                 file_name[n++] = tolower(temp[i]);
  395.             else
  396.                 file_name[n++] = temp[i];
  397.         }
  398.     }
  399.                     /* 3 character extension */
  400.     dot = 0;
  401.     for (i=8; i<11; i++) {
  402.         if (temp[i] != ' ') {
  403.             if (!dot) {
  404.                 dot++;
  405.                 file_name[n++] = '.';
  406.             }
  407.             if (isupper(temp[i]))
  408.                 file_name[n++] = tolower(temp[i]);
  409.             else
  410.                 file_name[n++] = temp[i];
  411.         }
  412.     }
  413.     file_name[n] = '\0';
  414.     return;
  415. }
  416.